package dev.http.httplient4;

import com.alibaba.fastjson.JSONObject;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.ParseException;
import org.apache.http.StatusLine;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLContext;
import javax.xml.bind.DatatypeConverter;
import java.io.*;
import java.nio.charset.Charset;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

/**
 * HttpClientNoSsl
 * HttpClient忽略SSL证书
 */
class HttpClientNoSsl {

    // 测试欧洲国家DHL接口
    private static int socketTimeout = 300000;// 请求超时时间

    private static int connectTimeout = 300000;// 传输超时时间

    public static void main(String[] args) throws Exception {

        String url = ""; // 请求地址

        try {
            // ==========1、发送get请求获取token
            // url = "xxxxxx"; //请求地址
            url = "http://xxxxx"; // 请求地址
            // String resultStr = doGetHttpClient(url);
            String resultStr = getNoSSL(url); // get请求(忽略SSL证书)，获取结果
            JSONObject jsonObj = JSONObject.parseObject(resultStr);
            String accessToken = jsonObj.getString("access_token");
            System.out.println("拿到token：" + accessToken);
            // ==========2、拿到token后，发送token和订单参数
            url = "https://xxxxxxx";
            // 获取这个类的路径path,参数有几十个字段，所以测试写死的放入文件里了
            // String path = "E:/dhl04.txt";
            String path = "E:/dhl05Str.txt";
            // path + "struts.xml"，就是类路径下的struts.xml这个文件了
            BufferedReader br = new BufferedReader(new FileReader(new File(path)));
            String s = "";
            String param = "";
            // 定义一个变量s，让s等于br去读一行。
            while ((s = br.readLine()) != null) {
                // System.out.println(s);
                param += s;
            }
            System.out.println("========请求参数========================");
            System.out.println(param);
            String resultXml = postNoSSL(url, param, accessToken);
            System.out.println("\n返回结果：\n" + resultXml);
        } catch (Exception ee) {
            System.out.println("错误===========" + ee);
        }

    }

    /**
     * 使用SOAP1.2发送消息
     *
     * @param postUrl
     * @param soapXml
     * @param token
     * @return
     */
    public static String doPostSoap(String postUrl, String soapXml, String token) {
        String retStr = "";
        try {
            //            CredentialsProvider provider = new BasicCredentialsProvider();
            //            UsernamePasswordCredentials credentials = new UsernamePasswordCredentials("ectms", "Zoot123!");
            //            provider.setCredentials(AuthScope.ANY, credentials);
            //            //创建HttpClientBuilder
            //            HttpClientBuilder httpClientBuilder = HttpClientBuilder.create().setDefaultCredentialsProvider(provider);
            //            // HttpClient
            //            CloseableHttpClient httpclient = httpClientBuilder.setRedirectStrategy(new LaxRedirectStrategy()).build();
            //            CloseableHttpClient closeableHttpClient = httpClientBuilder.build();
            //            1、创建httpClient
            CloseableHttpClient httpclient = HttpClients.createDefault();
            HttpPost httpPost = new HttpPost(postUrl);
            //头部添加token
            httpPost.setHeader("Authorization", "Bearer " + token);

            // 设置请求和传输超时时间
            RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build();

            httpPost.setConfig(requestConfig);

            httpPost.setHeader("Content-Type", "application/json;charset=UTF-8");
            //            httpPost.setHeader("SOAPAction", soapAction);
            StringEntity data = new StringEntity(soapXml, Charset.forName("UTF-8"));
            httpPost.setEntity(data);
            CloseableHttpResponse response = httpclient.execute(httpPost);
            HttpEntity httpEntity = response.getEntity();
            if (httpEntity != null) {
                // 打印响应内容
                retStr = EntityUtils.toString(httpEntity, "UTF-8");
            }
            // 释放资源
            httpclient.close();
        } catch (Exception e) {
            System.out.println("请求失败：/n" + e);
        }
        return retStr;
    }

    public static String doGet(String url) throws ParseException, IOException {
        // String path = "http://xxx";
        String path = url;// 请求的url地址
        String resultStr = "";
        // 1.创建客户端访问服务器的httpclient对象 打开浏览器
        // 1、创建httpClient
        CloseableHttpClient httpclient = HttpClients.createDefault();
        // 2.以请求的连接地址创建get请求对象 浏览器中输入网址
        HttpGet httpget = new HttpGet(path);
        // username:password--->访问的用户名，密码,并使用base64进行加密，将加密的字节信息转化为string类型，encoding--->token
        String encoding = DatatypeConverter.printBase64Binary("xxx:xxx".getBytes("UTF-8"));
        httpget.setHeader("Authorization", "Basic " + encoding);
        // 3.向服务器端发送请求 并且获取响应对象 浏览器中输入网址点击回车
        HttpResponse response = httpclient.execute(httpget);
        // 4.获取响应对象中的响应码
        StatusLine statusLine = response.getStatusLine();// 获取请求对象中的响应行对象
        int responseCode = statusLine.getStatusCode();// 从状态行中获取状态码
        System.out.println(responseCode);
        if (responseCode == 200) {
            // 5. 可以接收和发送消息
            HttpEntity entity = response.getEntity();
            // 6.从消息载体对象中获取操作的读取流对象
            InputStream input = entity.getContent();
            BufferedReader br = new BufferedReader(new InputStreamReader(input));
            String str1 = br.readLine();
            String result = new String(str1.getBytes("gbk"), "utf-8");
            System.out.println("服务器的响应结果:" + result);
            resultStr = result;
            br.close();
            input.close();
            // 释放资源
            httpclient.close();
        } else {
            System.out.println("响应失败!");
        }
        return resultStr;
    }
    // =========================忽略SSL证书的POST, GET请求======================================

    public static String postNoSSL(String postUrl, String paramJson, String token) {
        String resultStr = "";  // 返回结果
        try {
            // 1、创建httpClient
            // CloseableHttpClient httpClient = HttpClients.createDefault();
            CloseableHttpClient buildSSLCloseableHttpClient = buildSSLCloseableHttpClient();
            System.setProperty("jsse.enableSNIExtension", "false");
            HttpPost httpPost = new HttpPost(postUrl);
            httpPost.setHeader("Authorization", "Bearer " + token);
            // 设置请求和传输超时时间
            RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build();
            httpPost.setConfig(requestConfig);
            httpPost.setHeader("Content-Type", "application/json;charset=UTF-8");
            // 放入请求参数
            StringEntity data = new StringEntity(paramJson, Charset.forName("UTF-8"));
            httpPost.setEntity(data);
            // 发送请求，接收结果
            CloseableHttpResponse response = buildSSLCloseableHttpClient.execute(httpPost);
            // 4.获取响应对象中的响应码
            StatusLine statusLine = response.getStatusLine();// 获取请求对象中的响应行对象
            int responseCode = statusLine.getStatusCode();// 从状态行中获取状态码
            System.out.println(responseCode);
            if (responseCode == 200) {
                // 打印响应内容
                resultStr = EntityUtils.toString(response.getEntity(), "UTF-8");
                // 5. 可以接收和发送消息
                HttpEntity entity = response.getEntity();
                // 6.从消息载体对象中获取操作的读取流对象
                InputStream input = entity.getContent();
            } else {
                System.out.println("响应失败! : " + response.toString());
            }
            buildSSLCloseableHttpClient.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resultStr;
    }

    /**
     * 忽略SSL证书的get请求
     */
    public static String getNoSSL(String url) {
        String resultStr = "";// 返回结果
        try {
            CloseableHttpClient buildSSLCloseableHttpClient = buildSSLCloseableHttpClient();
            System.setProperty("jsse.enableSNIExtension", "false");
            HttpGet httpGet = new HttpGet(url);
            // username:password--->访问的用户名，密码,并使用base64进行加密，将加密的字节信息转化为string类型，encoding--->token
            String encoding = DatatypeConverter.printBase64Binary("ed800cb6-f012-478a-ad94-e095adb74677:9c1f4563-589e-4494-a182-3f1c4b321c29".getBytes("UTF-8"));
            // httpget.setHeader("username", "ed800cb6-f012-478a-ad94-e095adb74677");
            // httpget.setHeader("password", "9c1f4563-589e-4494-a182-3f1c4b321c29");
            httpGet.setHeader("Authorization", "Basic " + encoding);
            HttpResponse response = buildSSLCloseableHttpClient.execute(httpGet);
            // 4.获取响应对象中的响应码
            StatusLine statusLine = response.getStatusLine();// 获取请求对象中的响应行对象
            int responseCode = statusLine.getStatusCode();// 从状态行中获取状态码
            System.out.println(responseCode);
            if (responseCode == 200) {
                // 5. 可以接收和发送消息
                HttpEntity entity = response.getEntity();
                // 6.从消息载体对象中获取操作的读取流对象
                InputStream input = entity.getContent();
                BufferedReader br = new BufferedReader(new InputStreamReader(input));
                String str1 = br.readLine();
                String result = new String(str1.getBytes("gbk"), "utf-8");
                System.out.println("服务器的响应结果:" + result);
                resultStr = result;
                br.close();
                input.close();
                // 释放资源
                buildSSLCloseableHttpClient.close();
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return resultStr;

    }

    /**
     * 忽略证书
     */
    private static CloseableHttpClient buildSSLCloseableHttpClient() throws Exception {
        SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
            // 信任所有
            @Override
            public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                return true;
            }
        }).build();
        // ALLOW_ALL_HOSTNAME_VERIFIER:这个主机名验证器基本上是关闭主机名验证的,实现的是一个空操作，并且不会抛出javax.net.ssl.SSLException异常。
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, new String[]{"TLSv1"}, null, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
        return HttpClients.custom().setSSLSocketFactory(sslsf).build();
    }

}
